--[[

PackMove.lua

Move items between packs.

]]

-- Function: Swap two items in the same pack.
function LPS_SwapItems(packNumber, itemSlot1, itemSlot2)
	if (GetContainerItemLink(packNumber, itemSlot1) ~= nil) then
		LPS_SF_MoveItem(packNumber, itemSlot1, packNumber, itemSlot2);
	else
		LPS_SF_MoveItem(packNumber, itemSlot2, packNumber, itemSlot1);
	end
end

-- Function: Check two item names and return if they should be swapped.
function LPS_CheckNames(link1, link2)
	if (link1 == nil) then
		if (link2 ~= nil) then
			return true;
		end
	else
		if (link2 ~= nil) then
			local value1 = LPS_SF_LinkToName(link1);
			local value2 = LPS_SF_LinkToName(link2);
	
			if (LPS_Config.lowestfirst) then
				if (value1 > value2) then
					return true;
				end
			else
				if (value1 < value2) then
					return true;
				end
			end
		end
	end
	
	return false;
end

-- Function: Main pack sorting routine
function LPS_SortByType(myPack, pSlot1, pSlot2)
	local packRef		= "pack"..myPack;

	-- Set initial values for value1 and value2, these values mean if we fall-through here, we reject the sort.
	local value1		= 0;
	local value2		= 0;

	-- Check to see if the pack is in the bank itself, if so set the packRef correctly.
	if (myPack == BANK_CONTAINER) then
		packRef = "packb0";
	elseif (myPack > NUM_BAG_SLOTS) then
		packRef	= "packb"..(myPack - NUM_BAG_SLOTS);
	end

	-- If sort type is null, return false
	if (LPS_Config[packRef] == 0) then
		mySort = nil;
		return false;

	-- Sort by item value.
	elseif (LPS_Config[packRef] == 1) then
		local link1 = GetContainerItemLink(myPack, pSlot1);
		local link2 = GetContainerItemLink(myPack, pSlot2);

		if (link1 == nil) then
			if (link2 ~= nil) then
				return true;
			end
		else
			if (link2 ~= nil) then
				local _,count1 = GetContainerItemInfo(myPack, pSlot1);
				local _,count2 = GetContainerItemInfo(myPack, pSlot2);

				_, _, _, _, _, _, _, _, _, _, value1	= GetItemInfo(link1);
				if (value1 == nil) then
					value1 = 0;
				end
				value1					= value1 * count1;

				_, _, _, _, _, _, _, _, _, _, value2	= GetItemInfo(link2);
				if (value2 == nil) then
					value2 = 0;
				end
				value2					= value2 * count2;
			else
				return false;
			end
		end

	-- Sort by item name.
	elseif (LPS_Config[packRef] == 2) then
		return LPS_CheckNames(GetContainerItemLink(myPack, pSlot1), GetContainerItemLink(myPack, pSlot2));

	-- Sort by "tradeskill" type
	elseif (LPS_Config[packRef] == 3) then
		mySort = LPS_SortByTradeskill;
		--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Pack:"..myPack..", Name: "..packRef..", Sort Type: By Tradeskill");
		trade = 1;

	-- Sort by item level.
	elseif (LPS_Config[packRef] == 4) then
		local link1 = GetContainerItemLink(myPack, pSlot1);
		local link2 = GetContainerItemLink(myPack, pSlot2);

		if (link1 == nil) then
			if (link2 ~= nil) then
				return true;
			end
		else
			if (link2 ~= nil) then
				local _, _, _, item1, _, _, _, _, _, _, _ = GetItemInfo(link1);
				local _, _, _, item2, _, _, _, _, _, _, _ = GetItemInfo(link2);
				value1 = item1;
				value2 = item2;
			else
				return false;
			end
		end
	end
	
	-- Do the checking for sorting.
	if (value1 == nil) then
		if (value2 ~= nil) then
			return true;
		end
	else
		if (value2 ~= nil) then
			if (value1 > value2) then
				if (LPS_Config.lowestfirst) then
					return true;
				else
					return false;
				end
			else
				if (value1 == value2) then
					return LPS_CheckNames(GetContainerItemLink(myPack, pSlot1), GetContainerItemLink(myPack, pSlot2));
				end
			end
		end
	end

	return false;
end

-- Function: Main program function.... the sort routine.
function LPS_SortPack()
	if (InCombatLockdown() == 1) then
		return;
	end

	local curPack, noMovesDone = LPS_PM_AutoSort();
	--DEFAULT_CHAT_FRAME:AddMessage(format("Pack: %s", curPack));

	if (LPS_BankOpen) then
		if ((noMovesDone) and (curPack == (NUM_BAG_SLOTS + NUM_BANKBAGSLOTS))) then
			LPS_ENABLE = false;
			DEFAULT_CHAT_FRAME:AddMessage(LPS_MSG_SORTCOMPLETE);
		end
	else
		if ((noMovesDone) and (curPack == NUM_BAG_SLOTS)) then
			LPS_ENABLE = false;
			DEFAULT_CHAT_FRAME:AddMessage(LPS_MSG_SORTCOMPLETE);
		end
	end
end

-- Function: Check to see if a specific bag has any space.  Returns true if space available.
function LPS_PM_CheckSpace(pack)
	local packSize = GetContainerNumSlots(pack);
	for slot = 1, packSize do
		local itemLink = GetContainerItemLink(pack, slot);
		if (itemLink == nil) then
			return true;
		end
	end

	return false;
end

-- Function: Checks if item is a Special item, if so, then move to the listed Special item pack.
-- This returns the opposite of expected, false means an item has been moved.
-- Special Items are Soulbound, Quest, Herb, Leather, Mineral, Cloth, and items from custom lists 1 and 2.
function LPS_PM_CheckSpecial(pack, slot)
	-- Debug
	--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Check specials for pack "..pack);
	
	-- Exit if we are looking at a bank bag, or packs not worn by the character.
	if ((pack == BANK_CONTAINER) or (pack > NUM_BAG_SLOTS)) then
		--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Pack should be ignored.");
		return true;
	end

	--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Processing pack.");

	local itemLink = GetContainerItemLink(pack, slot);
	if (itemLink == nil) then
		return true;
	end

	local _, _, realLink		= string.find(itemLink, "^.*(item:[0-9]+:[0-9]+:[0-9]+:[0-9]+).*$");
	local itemName, _, _, _, _, itemType, itemSubType, itemStack, _, _ = GetItemInfo(itemLink);
	local _, itemCount, _, _, _	= GetContainerItemInfo(pack, slot);

	-- Soulbound Item
	local isSB = LPS_SF_GetItemTooltipLine(pack, slot, ITEM_SOULBOUND);
	if (isSB) then
		if (LPS_Config.sbitemPack ~= -1) then
			if (LPS_Config.sbitemPack ~= pack) then
				if (LPS_PM_CheckSpace(LPS_Config.sbitemPack)) then
					PickupContainerItem(pack, slot);
					if (LPS_Config.sbitemPack == 0) then
						PutItemInBackpack();
					else
						PutItemInBag(getglobal("CharacterBag"..(LPS_Config.sbitemPack - 1).."Slot"):GetID());
					end
					return false;
				end
			end
		end
--		return true;
	end

	-- Quest Item Checking
	if (itemType == "Quest") then
		if (LPS_Config.questPack ~= -1) then
			if (LPS_Config.questPack ~= pack) then
				if (LPS_PM_CheckSpace(LPS_Config.questPack)) then
					PickupContainerItem(pack, slot);
					if (LPS_Config.questPack == 0) then
						PutItemInBackpack();
					else
						PutItemInBag(getglobal("CharacterBag"..(LPS_Config.questPack - 1).."Slot"):GetID());
					end
					return false;
				end
			end
		end
		return true;
	end
	
	-- Quest Item
	local isQuest = LPS_SF_GetItemTooltipLine(pack, slot, ITEM_BIND_QUEST);
	if (isQuest) then
		if (LPS_Config.questPack ~= -1) then
			if (LPS_Config.questPack ~= pack) then
				if (LPS_PM_CheckSpace(LPS_Config.questPack)) then
					PickupContainerItem(pack, slot);
					if (LPS_Config.questPack == 0) then
						PutItemInBackpack();
					else
						PutItemInBag(getglobal("CharacterBag"..(LPS_Config.questPack - 1).."Slot"):GetID());
					end
					return false;
				end
			end
		end
		return true;
	end

	-- This Item Begins a Quest
	local isQuest = LPS_SF_GetItemTooltipLine(pack, slot, ITEM_STARTS_QUEST);
	if (isQuest) then
		if (LPS_Config.questPack ~= -1) then
			if (LPS_Config.questPack ~= pack) then
				if (LPS_PM_CheckSpace(LPS_Config.questPack)) then
					PickupContainerItem(pack, slot);
					if (LPS_Config.questPack == 0) then
						PutItemInBackpack();
					else
						PutItemInBag(getglobal("CharacterBag"..(LPS_Config.questPack - 1).."Slot"):GetID());
					end
					return false;
				end
			end
		end
		return true;
	end

	-- General Trade Goods Sorting
	if (itemType == "Trade Goods") then
		-- Check for Herbs
		if (itemSubType == "Herb") then
			if (LPS_Config.herbsort ~= -1) then
				if (LPS_Config.herbsort ~= pack) then
					if (LPS_PM_CheckSpace(LPS_Config.herbsort)) then
						PickupContainerItem(pack, slot);
						if (LPS_Config.herbsort == 0) then
							PutItemInBackpack();
						else
							PutItemInBag(getglobal("CharacterBag"..(LPS_Config.herbsort - 1).."Slot"):GetID());
						end
						return false;
					end
				end
			end
		-- Check for Minerals
		elseif (itemSubType == "Metal & Stone") then
			if (LPS_Config.mineralsort ~= -1) then
				if (LPS_Config.mineralsort ~= pack) then
					if (LPS_PM_CheckSpace(LPS_Config.mineralsort)) then
						PickupContainerItem(pack, slot);
						if (LPS_Config.mineralsort == 0) then
							PutItemInBackpack();
						else
							PutItemInBag(getglobal("CharacterBag"..(LPS_Config.mineralsort - 1).."Slot"):GetID());
						end
						return false;
					end
				end
			end
		-- Check for Leather
		elseif (itemSubType == "Leather") then
			if (LPS_Config.leathersort ~= -1) then
				if (LPS_Config.leathersort ~= pack) then
					if (LPS_PM_CheckSpace(LPS_Config.leathersort)) then
						PickupContainerItem(pack, slot);
						if (LPS_Config.leathersort == 0) then
							PutItemInBackpack();
						else
							PutItemInBag(getglobal("CharacterBag"..(LPS_Config.leathersort - 1).."Slot"):GetID());
						end
						return false;
					end
				end
			end
			return true;
		-- Check for Cloth
		elseif (itemSubType == "Cloth") then
			if (LPS_Config.clothsort ~= -1) then
				if (LPS_Config.clothsort ~= pack) then
					if (LPS_PM_CheckSpace(LPS_Config.clothsort)) then
						PickupContainerItem(pack, slot);
						if (LPS_Config.clothsort == 0) then
							PutItemInBackpack();
						else
							PutItemInBag(getglobal("CharacterBag"..(LPS_Config.clothsort - 1).."Slot"):GetID());
						end
						return false;
					end
				end
			end
		-- Catchall for all other tradeskill items
		else
			if (LPS_Config.tradesort ~= -1) then
				if (LPS_Config.tradesort ~= pack) then
					if (LPS_PM_CheckSpace(LPS_Config.tradesort)) then
						PickupContainerItem(pack, slot);
						if (LPS_Config.tradesort == 0) then
							PutItemInBackpack();
						else
							PutItemInBag(getglobal("CharacterBag"..(LPS_Config.tradesort - 1).."Slot"):GetID());
						end
						return false;
					end
				end
			end
		end
		return true;
	end

	-- Gem Sorting
	if (itemType == "Gem") then
		if (LPS_Config.gemsort ~= -1) then
			if (LPS_Config.gemsort ~= pack) then
				if (LPS_PM_CheckSpace(LPS_Config.gemsort)) then
					PickupContainerItem(pack, slot);
					if (LPS_Config.gemsort == 0) then
						PutItemInBackpack();
					else
						PutItemInBag(getglobal("CharacterBag"..(LPS_Config.gemsort - 1).."Slot"):GetID());
					end
					return false;
				end
			end
		end
		return true;
	end

	-- Consumable Item Sorting
	if (itemType == "Consumable") then
		if (LPS_Config.consumablesort ~= -1) then
			if (LPS_Config.consumablesort ~= pack) then
				if (LPS_PM_CheckSpace(LPS_Config.consumablesort)) then
					PickupContainerItem(pack, slot);
					if (LPS_Config.consumablesort == 0) then
						PutItemInBackpack();
					else
						PutItemInBag(getglobal("CharacterBag"..(LPS_Config.consumablesort - 1).."Slot"):GetID());
					end
					return false;
				end
			end
		end
		return true;
	end

	-- Debug Stuff
	--DEFAULT_CHAT_FRAME:AddMessage("LPS: "..itemName..", "..itemCount.."/"..itemStack..", itemType: "..itemType..", itemSubType: "..itemSubType);
	--DEFAULT_CHAT_FRAME:AddMessage("LPS: itemCount: "..itemCount);
	
	return true;
end

-- Function: Sort a given pack
local function LPS_PM_SortGivenPack(myPack)
	local packSize		= GetContainerNumSlots(myPack);
	local packRef		= "pack"..myPack;
	local trade		= 0;
	local emptySlot		= 0;
	local noMovesDone	= true;

	for slot = 1, (packSize - 1) do
		if ((GetContainerItemLink(myPack, slot) == nil) and (emptySlot == 0)) then
			emptySlot = slot;
		end

		if (noMovesDone) then
			noMovesDone = LPS_PM_CheckSpecial(myPack, slot);
		end

		if (noMovesDone) then
			local slot2 = slot + 1;

			noMovesDone = LPS_PM_CheckSpecial(myPack, slot2);

			if (noMovesDone) then
				if (LPS_SortByType(myPack, slot, slot2)) then
					if (emptySlot == 0) then
						LPS_SwapItems(myPack, slot, slot2);
					else
						LPS_SwapItems(myPack, emptySlot, slot2);
						emptySlot = 0;
					end
					noMovesDone = false;
				end
			end
		end
	end

	return noMovesDone;
end

-- Function: Handle the "auto-sort" routine
function LPS_PM_AutoSort()
	local noMovesDone	= true;
	local mySort		= nil;
	local myPack		= 0;
	local trade		= 0;

	-- Set the "Normal" start/stop values
	local startBag		= 0;			-- normal start bag value
	local endBag		= NUM_BAG_SLOTS;	-- normal max bag value

	-- Check to see if bank is open, if so, use the maximum value for bag slots, otherwise, use normal values.
	if (LPS_BankOpen) then
		startBag	= BANK_CONTAINER;
		endBag		= NUM_BAG_SLOTS + NUM_BANKBAGSLOTS;
	end

	for pack = startBag, endBag do
		if (LPS_PM_SortGivenPack(pack) == false) then
			noMovesDone	= false;
--			return pack, noMovesDone;
		else
			myPack		= pack;
--			return pack, noMovesDone;
		end
	end

	return myPack, noMovesDone;
end

--[[
Guild bank functions
]]
-- Function: Check to see if the two items need to be swapped.  Checking by Name.
local function LPS_SortGBByName(tab, slot1, slot2)
	return LPS_CheckNames(GetGuildBankItemLink(tab, slot1), GetGuildBankItemLink(tab, slot2));
end

-- Function: Check to see if the two items need to be swapped.  Checking by iLevel.
local function LPS_SortGBByiLevel(tab, slot1, slot2)
	local link1 = GetGuildBankItemLink(tab, slot1);
	local link2 = GetGuildBankItemLink(tab, slot2);

	if (link1 == nil) then
		if (link2 ~= nil) then
			return true;
		end
	else
		if (link2 ~= nil) then
			local _, _, _, item1, _, _, _, _, _, _, _ = GetItemInfo(GetGuildBankItemLink(tab, slot1));
			local _, _, _, item2, _, _, _, _, _, _, _ = GetItemInfo(GetGuildBankItemLink(tab, slot2));
			
			if (LPS_Config.lowestfirst) then
				if (item1 > item2) then
					return true;
				elseif (item1 == item2) then
					return LPS_SortGBByName(tab, slot1, slot2);
				end
			else
				if (item1 < item2) then
					return true;
				elseif (item1 == item2) then
					return LPS_SortGBByName(tab, slot1, slot2);
				end
			end
		else
			return false;
		end
	end

	return false;
end


--[[
This function can be fairly dangerous to allow anyone to use, so for the time being it's a "hidden" function,
and not available to people who don't read the source code...
]]
function LPS_PM_SortOpenGuildBankTab(sortType)
	local guildTab		= GetCurrentGuildBankTab();
--	local packSize		= GetContainerNumSlots(myPack);
--	local packRef		= "pack"..myPack;
	local trade		= 0;
	local emptySlot		= 0;
	local noMovesDone	= true;
		
	if (sortType == 0) then
		mySort = nil;
		--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab:"..guildTab..", Sort Type: Nil");
	elseif (sortType == 1) then
		mySort = LPS_SortByPrice;
		--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab:"..guildTab..", Sort Type: By Price");
	elseif (sortType == 2) then
		mySort = LPS_SortGBByName;
		--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab:"..guildTab..", Sort Type: By Name");
	elseif (sortType == 3) then
		mySort = LPS_SortByTradeskill;
		--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab:"..guildTab..", Sort Type: By Tradeskill");
		trade = 1;
	elseif (sortType == 4) then
		mySort = LPS_SortGBByiLevel;
		--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab:"..guildTab..", Sort Type: By iLevel");
	else
		return;
	end

--	for guildTab = 1, GetNumGuildBankTabs() do
		for slot = 1, 97 do
			--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." Checking for valid item in slot "..slot);
			if ((GetGuildBankItemLink(guildTab, slot) == nil) and (emptySlot == 0)) then
				--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." Empty Slot found at Slot "..slot);
				emptySlot = slot;
			end

			if (noMovesDone) then
				--SetCurrentGuildBankTab(guildTab);
				local slot2 = slot + 1;

				--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." Checking for valid item in slot "..slot2);
				if (GetGuildBankItemLink(guildTab, slot2) ~= nil) then
					--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." Valid item found in slot "..slot2);
					if (noMovesDone) then
						--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." so far, noMovesDone");
						if (mySort ~= nil) then
							--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." Checking items in slots "..slot.." and "..slot2);
							if (mySort(guildTab, slot, slot2)) then
								if (emptySlot == 0) then
									--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." Swapping Items in slots "..slot.." and "..slot2);
									LPS_SF_MoveGBItem(guildTab, slot, slot2);
								else
									--DEFAULT_CHAT_FRAME:AddMessage("LPS Debug: Guild Tab: "..guildTab.." Moving item in slot "..slot2.." to the highest empty slot which should be "..emptySlot..".");
									LPS_SF_MoveGBItem(guildTab, slot2, emptySlot);
									emptySlot = 0;
								end
								noMovesDone = false;
							end
						end
					end
				end
			end
		end
--	end

	return noMovesDone;
end

-- Function: Main program function.... the sort routine.
function LPS_SortGBTab()
	LPS_GB_PauseSort = true;

	LPS_GBSortTime = time();
	
	local noMovesDone = LPS_PM_SortOpenGuildBankTab(LPS_Config.guild);

	if (noMovesDone) then
		LPS_GBSort = false;
		DEFAULT_CHAT_FRAME:AddMessage(LPS_MSG_SORTCOMPLETE);
	end

	LPS_GB_PauseSort = false;
end

